module Msimple_fifo_pre
#(
   parameter                RAM_TYPE   = "REG"
  ,parameter                ADDR_WIDTH = 1
  ,parameter                DATA_WIDTH = 1
  ,parameter                DATA_DEPTH = 1
)
(
  // clk and rst
   input                    i_clk
  ,input                    i_rst_n
  // write signal
  ,input                    i_wr
  ,input  [DATA_WIDTH-1:0]  i_wdata
  ,output                   o_full
  ,output [ADDR_WIDTH:0]    o_remain
  // read signal
  ,input                    i_rd
  ,output [DATA_WIDTH-1:0]  o_rdata
  ,output                   o_empty
  ,output [ADDR_WIDTH:0]    o_use
  // unusual
  ,output                   o_overflow
  ,output                   o_underflow
  ,output                   o_wrd_err
);
//==========================================================
// ver                                            start//{{{
//==========================================================
reg                         rd_r                           ;
reg                         bypass_w                       ;
reg                         outreg_en_r                    ;
reg       [DATA_WIDTH-1:0]  outreg_r                       ;

wire                        fifo_wr                        ;
wire      [DATA_WIDTH-1:0]  fifo_wdata                     ;
wire                        fifo_full                      ;
wire      [ADDR_WIDTH:0]    fifo_remain                    ;
wire                        fifo_rd                        ;
wire      [DATA_WIDTH-1:0]  fifo_rdata                     ;
wire                        fifo_empty                     ;
wire      [ADDR_WIDTH:0]    fifo_use                       ;
wire                        fifo_overflow                  ;
wire                        fifo_underflow                 ;
wire                        fifo_wrd_err                   ;
//==========================================================
// ver                                              end//}}}
//==========================================================

//==========================================================
// write                                          start//{{{
//==========================================================
assign fifo_wr    = i_wr & (~bypass_w)                     ;
assign fifo_wdata = i_wdata                                ;
assign o_full     = fifo_full                              ;
assign o_remain   = fifo_remain + {{DATA_WIDTH-1{1'd0}},~outreg_en_r};
//==========================================================
// write                                            end//}}}
//==========================================================

//==========================================================
// read                                           start//{{{
//==========================================================
always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    rd_r <= 1'd0;
  end
  else begin
    rd_r <= i_rd && (~fifo_empty);
  end
end

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    outreg_en_r <= 1'd0;
  end
  else if(bypass_w && i_wr) begin
    outreg_en_r <= 1'd1;
  end
  else if(rd_r && (~i_rd)) begin
    outreg_en_r <= 1'd1;
  end
  else if(i_rd) begin
    outreg_en_r <= 1'd0;
  end
end

always@(posedge i_clk) begin
  if(i_rst_n == 1'd0) begin
    outreg_r <= {DATA_WIDTH{1'd0}};
  end
  else if(bypass_w && i_wr) begin
    outreg_r <= i_wdata;
  end
  else if(rd_r && (~i_rd)) begin
    outreg_r <= fifo_rdata;
  end
end

assign bypass_w   = fifo_empty && (~outreg_en_r) && (~(rd_r && (~i_rd)));

assign fifo_rd    = i_rd & (~fifo_empty)                   ;
assign o_rdata    = outreg_en_r ? outreg_r : fifo_rdata    ;
assign o_empty    = fifo_empty & (~outreg_en_r)            ;
assign o_use      = fifo_use + {{DATA_WIDTH-1{1'd0}},outreg_en_r};
//==========================================================
// read                                             end//}}}
//==========================================================

assign o_overflow  = fifo_overflow                         ;
assign o_underflow = fifo_underflow                        ;
assign o_wrd_err   = fifo_wrd_err                          ;

//==========================================================
// fifo                                           start//{{{
//==========================================================
Msimple_fifo
#(
   .RAM_TYPE                ( RAM_TYPE                     )
  ,.ADDR_WIDTH              ( ADDR_WIDTH                   )
  ,.DATA_WIDTH              ( DATA_WIDTH                   )
  ,.DATA_DEPTH              ( DATA_DEPTH                   )
)
M_simple_fifo
(
  // clk and rst
   .i_clk                   ( i_clk                        )
  ,.i_rst_n                 ( i_rst_n                      )
  // write signal
  ,.i_wr                    ( fifo_wr                      )
  ,.i_wdata                 ( fifo_wdata                   )
  ,.o_full                  ( fifo_full                    )
  ,.o_remain                ( fifo_remain                  )
  // read signal
  ,.i_rd                    ( fifo_rd                      )
  ,.o_rdata                 ( fifo_rdata                   )
  ,.o_empty                 ( fifo_empty                   )
  ,.o_use                   ( fifo_use                     )
  // unusual
  ,.o_overflow              ( fifo_overflow                )
  ,.o_underflow             ( fifo_underflow               )
  ,.o_wrd_err               ( fifo_wrd_err                 )
);
//==========================================================
// fifo                                             end//}}}
//==========================================================

endmodule
